package com.eapi.project.service.impl;

import cn.hutool.core.util.RandomUtil;
import cn.hutool.crypto.digest.DigestUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.eapi.project.constant.UserConstant;
import com.eapi.project.exception.BusinessException;
import com.eapi.project.service.UserService;
import com.eapi.eapicommom.model.entity.User;
import com.eapi.project.common.ErrorCode;
import com.eapi.project.mapper.UserMapper;
import com.eapi.project.model.dto.user.UserBuyPointsRequest;
import com.eapi.project.model.entity.Identifycode;
import com.eapi.project.service.IdentifycodeService;
import com.eapi.project.utils.JedisPoolUtil;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.connection.PoolConfig;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.DigestUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
import redis.clients.jedis.params.SetParams;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Type;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;


/**
 * 用户服务实现类
 *
 * @author yupi
 */
@Service
@Slf4j
public class UserServiceImpl extends ServiceImpl<UserMapper, User>
        implements UserService {

    // private Jedis jedis = new Jedis("r-bp1yjtnfoml2vk5nrspd.redis.rds.aliyuncs.com", 6379);
    // String jedisAuth = jedis.auth("Zhang031101");


    private static final String HOST = "r-bp1v85gr0c6p7oicvkpd.redis.rds.aliyuncs.com";
    private static final int PORT = 6379;

    private static final String AUTH = "Zhang031101";

    private static volatile JedisPool jedisPool = null;

    static {
        jedisPool = getJedisPoolInstance();
    }

    /**
     * 获取RedisPool实例（单例）
     * @return RedisPool实例
     */
    public static JedisPool getJedisPoolInstance() {
        if (jedisPool == null) {
            synchronized (UserServiceImpl.class) {
                if (jedisPool == null) {
                    JedisPoolConfig poolConfig = new JedisPoolConfig();
                    poolConfig.setMaxTotal(1000);           // 最大连接数
                    poolConfig.setMaxIdle(32);              // 最大空闲连接数
                    poolConfig.setMaxWaitMillis(100*10000);  // 最大等待时间
                    poolConfig.setTestOnBorrow(true);       // 检查连接可用性, 确保获取的redis实例可用
                    jedisPool = new JedisPool(poolConfig, HOST, PORT, 10000000, AUTH);
                }
            }
        }

        return jedisPool;
    }
    Jedis jedis = null;


    @Resource
    private UserMapper userMapper;

    @Resource
    private IdentifycodeService identifycodeService;

    /**
     * 盐值，混淆密码
     */
    private static final String SALT = "yupi";

    @Override
    public long userRegister(String userAccount, String userPassword, String checkPassword, String emailAddress, String identifyCode) {
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword, checkPassword, emailAddress, identifyCode)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户账号过短");
        }
        if (userPassword.length() < 8 || checkPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户密码过短");
        }
        // 密码和校验密码相同
        if (!userPassword.equals(checkPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "两次输入的密码不一致");
        }
        synchronized (userAccount.intern()) {
            // 判断验证码是否正确
            QueryWrapper<Identifycode> inentifyQueryWrapper = new QueryWrapper<>();
            inentifyQueryWrapper.eq("emailaddress", emailAddress);
            Identifycode inentify = identifycodeService.getOne(inentifyQueryWrapper); // 查询验证码
            String correctIdentifyCode = inentify.getIdentifycode();
            if (!identifyCode.equals(correctIdentifyCode)) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "验证码错误");
            }
            // 账户不能重复
            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userAccount", userAccount);
            long count = userMapper.selectCount(queryWrapper);
            if (count > 0) {
                throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号重复");
            }
            // 2. 加密
            String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
            // 3.分配accessKey,SecretKey
            // 根据用户的账号 + 随机数进行accessKey的生成
            String accessKey = DigestUtil.md5Hex(SALT + userAccount + RandomUtil.randomNumbers(5));
            String secretKey = DigestUtil.md5Hex(SALT + userAccount + RandomUtil.randomNumbers(8));
            // 4. 插入数据
            User user = new User();
            user.setUserAccount(userAccount);
            user.setUserPassword(encryptPassword);
            user.setAccessKey(accessKey);
            user.setSecretKey(secretKey);
            user.setEmailAddress(emailAddress);
            boolean saveResult = this.save(user);
            if (!saveResult) {
                throw new BusinessException(ErrorCode.SYSTEM_ERROR, "注册失败，数据库错误");
            }
            return user.getId();
        }
    }

    @Override
    public User userLogin(String userAccount, String userPassword, HttpServletRequest request) {
        // 1. 校验
        if (StringUtils.isAnyBlank(userAccount, userPassword)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "参数为空");
        }
        if (userAccount.length() < 4) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "账号错误");
        }
        if (userPassword.length() < 8) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "密码错误");
        }
        // 2. 加密
        String encryptPassword = DigestUtils.md5DigestAsHex((SALT + userPassword).getBytes());
        // 查询用户是否存在
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("userAccount", userAccount);
        queryWrapper.eq("userPassword", encryptPassword);
        User user = userMapper.selectOne(queryWrapper);
        // 用户不存在
        if (user == null) {
            log.info("user login failed, userAccount cannot match userPassword");
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "用户不存在或密码错误");
        }
        // 3. 记录用户的登录态
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);
        try {
            //jedisPool建议封装成工具类；并采用单例模式（桌静态对象）
            jedis = jedisPool.getResource();  // 获取Redus连接
            String jedisAuth = jedis.auth(AUTH);
            jedis.set(user.getUserAccount(), user.getUserAccount(), new SetParams().px(300000L));
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            if(jedis != null){
                //jedisPool.returnResourceObject(jedis);  // 已废弃，推荐使用jedis.close()方法
                jedis.close(); // 关闭redis连接,还回redis连接池中；
            }
        }
        return user;
    }

    @Override
    public User userLoginByEmail(String emailAddress, String identifyCode, HttpServletRequest request) {
        // 判断验证码是否正确
        QueryWrapper<Identifycode> inentifyQueryWrapper = new QueryWrapper<>();
        inentifyQueryWrapper.eq("emailaddress", emailAddress);
        Identifycode inentify = identifycodeService.getOne(inentifyQueryWrapper); // 查询验证码
        String correctIdentifyCode = inentify.getIdentifycode();
        if (!identifyCode.equals(correctIdentifyCode)) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "验证码错误");
        }
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("emailAddress", emailAddress);
        User user = userMapper.selectOne(queryWrapper);
        // 3. 记录用户的登录态
        request.getSession().setAttribute(UserConstant.USER_LOGIN_STATE, user);
        try {
            //jedisPool建议封装成工具类；并采用单例模式（桌静态对象）
            jedis = jedisPool.getResource();  // 获取Redus连接
            String jedisAuth = jedis.auth(AUTH);
            jedis.set(user.getUserAccount(), user.getUserAccount(), new SetParams().px(600000L));
        }catch(Exception e){
            e.printStackTrace();
        } finally {
            if(jedis != null){
                //jedisPool.returnResourceObject(jedis);  // 已废弃，推荐使用jedis.close()方法
                jedis.close(); // 关闭redis连接,还回redis连接池中；
            }
        }
        return user;
    }



    /**
     * 获取当前登录用户
     *
     * @param request
     * @return
     */
    @Override
    public User getLoginUser(HttpServletRequest request) {
        if(request.getHeader("JWT") == null){
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        String jwt = request.getHeader("JWT");

        try (Jedis jedis = jedisPool.getResource()) {
            String jedisAuth = jedis.auth(AUTH);
            if (!jedis.exists(jwt)) {
                throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
            }

            QueryWrapper<User> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("userAccount", jwt);
            User currentUser = userMapper.selectOne(queryWrapper);
            long userId = currentUser.getId();
            currentUser = this.getById(userId);

            if (currentUser == null) {
                throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
            }
            jedis.set(currentUser.getUserAccount(), currentUser.getUserAccount(), new SetParams().px(600000L));
            return currentUser;
        } catch (Exception e) {
            log.error("Error while getting logged in user", e);
            throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
        }
        // 先判断是否已登录
        // Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
    /*String jwt = request.getHeader("JWT");
    if (!jedis.exists(jwt)) {
        throw new BusinessException(ErrorCode.NOT_LOGIN_ERROR);
    }*/

    }
    /**
     * 是否为管理员
     *
     * @param request
     * @return
     */
    @Override
    public boolean isAdmin(HttpServletRequest request) {
        // 仅管理员可查询
        Object userObj = request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE);
        User user = (User) userObj;
        return user != null && UserConstant.ADMIN_ROLE.equals(user.getUserRole());
    }

    /**
     * 用户注销
     *
     * @param request
     */
    @Override
    public boolean userLogout(HttpServletRequest request) {
    /*if (request.getSession().getAttribute(UserConstant.USER_LOGIN_STATE) == null) {
        throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");
    }*/
        jedis = jedisPool.getResource();  // 获取Redus连接
        String jedisAuth = jedis.auth(AUTH);
        String jwt = request.getHeader("JWT");
        if (jedis.exists(jwt)) {
            jedis.del(jwt);
        } else {
            throw new BusinessException(ErrorCode.OPERATION_ERROR, "未登录");
        }
        // 移除登录态
        request.getSession().removeAttribute(UserConstant.USER_LOGIN_STATE);
        return true;
    }


    @Override
    public boolean buyPoints(int points, Long userId) {
        if (points <= 0) {
            throw new BusinessException(ErrorCode.PARAMS_ERROR, "积分数量错误");
        }
        UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
        updateWrapper.eq("id", userId);
        updateWrapper.setSql("remainingPoints = remainingPoints + " + points);
        boolean update = this.update(updateWrapper);
        return update;
    }

    @Override
    public boolean buildBill(String out_trade_no, Long userId) {
        try {
            //jedisPool建议封装成工具类；并采用单例模式（桌静态对象）
            jedis = jedisPool.getResource();  // 获取Redus连接
            String jedisAuth = jedis.auth(AUTH);
            Map<String,String> map = new HashMap<>();
            map.put(userId.toString(),out_trade_no);
            Long hset = jedis.hset(out_trade_no,map);
        }catch(Exception e){
            e.printStackTrace();
        } finally {
           if(jedis != null){
                //jedisPool.returnResourceObject(jedis);  // 已废弃，推荐使用jedis.close()方法
                jedis.close(); // 关闭redis连接,还回redis连接池中；
            }
        }
        return false;
    }
}




